package com.itheima.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.itheima.reggie.common.BaseContext;
import com.itheima.reggie.common.R;
import jdk.dynalink.beans.StaticClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.file.PathMatcher;

//前者是过滤器名字，随便写，后者是过滤的路劲，这里设置的是全部拦截
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")   // 过滤器注解
@Slf4j   // 输出日志，类似于 log4j
public class LoginCheckFilter implements Filter {

    //使用路径匹配器，支持匹配路径通配符
    public static final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        /*
            注意 filter 是过滤器，作用的范围大，springMvc的拦截器（interceptor）只针对于Mvc的访问拦截（还需要进行静态资源的释放）
            可以将两者进行比较
            可以看出，以后还是 filter 方便，快捷省事
         */
        //将请求，响应参数进行向下转型，变为子类，子类实现的方法多
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //1.获取本次请求的URI（相对路径）    /backend/page/login/login.html
        //  获取本次请求的URL（绝对路径）    http://localhost:8080/backend/page/login/login.html
        System.out.println(request.getRequestURI());
        System.out.println(request.getRequestURL());
        String requestURI = request.getRequestURI();

        //输出日记，看是否拦截成功
        //这里的是输出不用 + 连接，逗号后面的替换 {} 这个占位符
        log.info("拦截到的请求：{}",requestURI);

        //定义不需要进行处理的请求的路径
        //注意这里前面 也需要一个 /，不然拦截不到！！！！！
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**",
                "/common/**",
                "/user/sendMsg",    //移动端发送短信验证码
                "/user/login",     //移动端用户登录
                "/doc.html",    // 下面这些是地址是 swagger 在线接口的的地址，需要释放（不然需要登录才能看）
                "/webjars/**",
                "/swagger-resources",
                "/v2/api-docs"
        };

        //2.判断本次请求是否需要进行处理，ture不拦截，false拦截
        boolean check = check(urls, requestURI);
        System.out.println(check);

        //3.对不需要拦截的路径进行放行
        if(check){
            log.info("本次请求{}不需要处理",requestURI);
            filterChain.doFilter(request,response);
            return;
        }

        //4-1.判断后端管理人员登录状态，如果已登录，则直接放行
        if(request.getSession().getAttribute("employee") != null){
            Long employeeId = (Long) request.getSession().getAttribute("employee");
            log.info("用户已登录，用户id为：{}", employeeId);
            log.info("线程id：{}",Thread.currentThread().getId());

            //进行保存用户得id，通过http请求线程，供给 mp 得自动填充使用
            //进行保存用户得id，通过http请求线程，供给 mp 得自动填充使用
            //将 登陆的用户Id 保存到每一个请求得拦截得页面（登录状态），
            //也就说每一个进行拦截得页面 得 threadLocal 都保存着 登录用户Id
            //方便查询当前 用户得信息
            BaseContext.setCurrentThreadId(employeeId);
            log.info("修改之后得线程id：{}",BaseContext.getCurrentThreadId());

            filterChain.doFilter(request,response);
            return;
        }
        //4-2.判断移动端用户登录状态，如果已登录，则直接放行
        if(request.getSession().getAttribute("user") != null){
            Long userId = (Long) request.getSession().getAttribute("user");
            log.info("用户已登录，用户id为：{}", userId);
            log.info("线程id：{}",Thread.currentThread().getId());

            //进行保存用户得id，通过http请求线程，供给 mp 得自动填充、userId 使用
            //将 登陆的用户Id 保存到每一个请求得拦截得页面（登录状态），
            //也就说每一个进行拦截得页面 得 threadLocal 都保存着 登录用户Id
            //方便查询当前 用户得信息
            BaseContext.setCurrentThreadId(userId);
            log.info("修改之后得线程id：{}",BaseContext.getCurrentThreadId());

            filterChain.doFilter(request,response);
            return;
        }

        //5、如果未登录则返回未登录结果，通过输出流方式向客户端页面响应数据
        log.info("用户未登录");
        //返回json对象给前端，request.js 页面会进行处理
        //就是如果直接去登录首页，request.js 接受 msg 信息之后，跳转到登录的页面
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;
    }

    /**
     * 通过路径匹配对象进行判断是否是不拦截或拦截的路径
     * @param urls  不拦截的路径
     * @param requestURI  请求的路径
     * @return
     */
    public boolean check(String[] urls,String requestURI){
        for (String url : urls) {
            boolean check = pathMatcher.match(url, requestURI);
            if (check){
                return true;
            }
        }
        return false;
    }
}
